/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfast.framework.aop;
import java.io.Serializable;
import java.util.List;


import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.ProvidedBy;
import com.google.inject.matcher.Matchers;
import com.google.inject.name.Names;
import com.jfast.framework.aop.annotation.Bean;
import com.jfast.framework.kit.StrKit;
import com.jfast.framework.orm.query.DefaultJdbcTemplate;
import com.jfast.framework.orm.query.JdbcTemplate;
import com.jfast.framework.util.ClassScanner;
import com.jfast.framework.web.annotation.ConfigurationProperties;
import com.jfast.framework.web.config.JfastConfigManager;
import com.jfast.framework.orm.TxInterceptor;
import com.jfast.framework.orm.annotation.Transaction;

/**
 * guice管理器
 * @author zengjintao
 * @version 1.0
 * 2017年10月13日下午8:29:28
 */
public class GuiceManager implements com.google.inject.Module {
	
	private static final GuiceManager guiceManger = new GuiceManager();
	
	private Injector injector ;
	
	private GuiceManager() {
		injector = Guice.createInjector(this);
	}
	
	public static GuiceManager getGuiceManger() {
		return guiceManger;
	}
	
	public Injector getInjector() {
		return injector;
	}

	@Override
	public void configure(Binder binder) {
		binderInterceptor(binder);
		bindBean(binder);
		binderConfiguration(binder);
		binderProvider(binder);
	}

	/**
	 * guice Provider绑定
	 * @param binder
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void binderProvider(Binder binder) {
		List<Class<?>> providerClasses = ClassScanner.getClassByAnnoation(ProvidedBy.class);
		for (Class clazz : providerClasses) {
			ProvidedBy providedBy = (ProvidedBy) clazz.getAnnotation(ProvidedBy.class);
			binder.bind(clazz).toProvider(providedBy.value());
		}
	}

	/**
	 * guice拦截器绑定
	 * @param binder
	 */
	private void binderInterceptor(Binder binder) {
		binder.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transaction.class), new TxInterceptor());
	}

	/**
	 * guice类实例绑定
	 * @param binder
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void binderConfiguration(Binder binder) {
		List<Class<?>> classes = ClassScanner.getClassByAnnoation(ConfigurationProperties.class);
		for (Class clazz : classes) {
			Object object = JfastConfigManager.createConfigBean(clazz);
			binder.bind(clazz).toInstance(object);
		}
	}

	/**
	 * 
	 * guice Bean绑定
	 * @param binder
	 */
	@SuppressWarnings({"unchecked", "rawtypes" })
	private void bindBean(Binder binder) {
		binder.bind(JdbcTemplate.class).to(DefaultJdbcTemplate.class);
		List<Class<?>> list = ClassScanner.getClassByAnnoation(Bean.class);
		for (Class<?> beanClass : list) {
			Bean bean = beanClass.getAnnotation(Bean.class);
			Class<?>[] interfaceClasses = beanClass.getInterfaces();
			for (Class interfaceClass : interfaceClasses) {
				if (interfaceClass == Serializable.class) {
                    continue;
                }
				try {
					if (StrKit.isEmpty(bean.value()))
						binder.bind(interfaceClass).to(beanClass);
					else
						binder.bind(interfaceClass).annotatedWith(Names.named(bean.value())).to(beanClass);
				} catch (Exception e) {
					System.err.println(String.format("can not bind [%s] to [%s]", interfaceClass, beanClass));
				}
			}
		}
	}
}
